home *** CD-ROM | disk | FTP | other *** search
/ Freelog 22 / freelog 22.iso / Prog / Djgpp / GPC2952B.ZIP / lib / gcc-lib / djgpp / 2.952 / units / system.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2001-02-08  |  20.5 KB  |  730 lines

  1. {
  2. BP compatible System unit for GPC
  3.  
  4. This unit is released as part of the GNU Pascal project. It
  5. implements some rather exotic BP compatibility features. Even many
  6. BP programs don't need them, but they're here for maximum
  7. compatibility. Most of BP's System unit's features are built into
  8. the compiler or the RTS.
  9.  
  10. The unit depends on the conditional defines `__BP_TYPE_SIZES__' and
  11. `__BP_RANDOM__'. If `__BP_TYPE_SIZES__' is defined (with the
  12. `-D__BP_TYPE_SIZES__' option), the integer data types will be
  13. redefined to the sizes they have in BP or Delphi. Note that this
  14. might cause problems, e.g. when passing var parameters of integer
  15. types between units that do and don't use System. However, of the BP
  16. compatibility units, only Dos and WinDos use such parameters, and
  17. they have been taken care of so they work.
  18.  
  19. If `__BP_RANDOM__' is defined (`-D__BP_RANDOM__'), this unit will
  20. provide an exactly BP compatible pseudo random number generator. In
  21. particular, the range for integer randoms will be truncated to 16
  22. bits like in BP. The RandSeed variable is provided, and if it's set
  23. to the same value as BP's RandSeed, it produces exactly the same
  24. sequence of pseudo random numbers that BP's pseudo random number
  25. generator does (whoever might need this... ;-). Even the Randomize
  26. function will behave exactly like in BP. However, this will not be
  27. noted unless one explicitly tests for it.
  28.  
  29. Copyright (C) 1998-2001 Free Software Foundation, Inc.
  30.  
  31. Authors: Peter Gerwinski <peter@gerwinski.de>
  32.          Prof. Abimbola A. Olowofoyeku <African_Chief@bigfoot.com>
  33.          Frank Heckenbach <frank@pascal.gnu.de>
  34.          Dominik Freche <dominik.freche@gmx.net>
  35.  
  36. This file is part of GNU Pascal.
  37.  
  38. GNU Pascal is free software; you can redistribute it and/or modify
  39. it under the terms of the GNU General Public License as published by
  40. the Free Software Foundation; either version 2, or (at your option)
  41. any later version.
  42.  
  43. GNU Pascal is distributed in the hope that it will be useful,
  44. but WITHOUT ANY WARRANTY; without even the implied warranty of
  45. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  46. GNU General Public License for more details.
  47.  
  48. You should have received a copy of the GNU General Public License
  49. along with GNU Pascal; see the file COPYING. If not, write to the
  50. Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
  51. 02111-1307, USA.
  52.  
  53. As a special exception, if you link this file with files compiled
  54. with a GNU compiler to produce an executable, this does not cause
  55. the resulting executable to be covered by the GNU General Public
  56. License. This exception does not however invalidate any other
  57. reasons why the executable file might be covered by the GNU General
  58. Public License.
  59. }
  60.  
  61. {$gnu-pascal,B-,I-}
  62. {$if __GPC_RELEASE__ < 20000412}
  63. {$error This unit requires GPC release 20000412 or newer.}
  64. {$endif}
  65.  
  66. unit System;
  67.  
  68. interface
  69.  
  70. uses GPC;
  71.  
  72. var
  73.   { Chain of procedures to be executed at the end of the program }
  74.   ExitProc : ^procedure = nil;
  75.  
  76.   { Contains all the command line arguments passed to the program,
  77.     concatenated, with spaces between them }
  78.   CmdLine : CString;
  79.  
  80.   {$ifdef __BP_RANDOM__}
  81.   { Random seed, initialized by Randomize, but can also be set
  82.     explicitly }
  83.   RandSeed : Integer (32) = 0;
  84.   {$endif}
  85.  
  86. type
  87.   OrigInt = Integer;
  88.   OrigWord = Word;
  89.  
  90.   { needed in the Dos unit }
  91.   Int7 = Integer (7);
  92.   Word16 = Word (16);
  93.   Word32 = Word (32);
  94.  
  95.   { Delphi }
  96.   SmallInt = Integer  (16);
  97.   DWord    = Cardinal (32);
  98.  
  99.   { Short BP compatible type sizes if wanted }
  100.   {$ifdef __BP_TYPE_SIZES__}
  101.   ByteBool = Boolean  (8);
  102.   WordBool = Boolean  (16);
  103.   LongBool = Boolean  (32);
  104.   Boolean  = ByteBool;      { important in packed records and arrays }
  105.   ShortInt = Integer  (8);
  106.   Byte     = Cardinal (8);
  107.   Word     = Cardinal (16);
  108.   LongInt  = Integer  (32);
  109.   Comp     = Integer  (64);
  110.   LongWord = Cardinal (32); { Delphi }
  111.   Integer  = Integer  (16);
  112.   {$endif}
  113.  
  114.   (*@@ doesn't work well (dialec3.pas) -- when GPC gets short
  115.        strings, it will be unnecessary
  116.   {$ifdef __BORLAND_PASCAL__}
  117.   String = String [255];
  118.   {$endif} *)
  119.  
  120. const
  121.   MaxInt     = High (Integer);
  122.   MaxLongInt = High (LongInt);
  123.  
  124. { Return the lowest-order byte of x }
  125. function  Lo (x : LongestInt) : Byte;
  126.  
  127. { Return the lowest-but-one-order byte of x }
  128. function  Hi (x : LongestInt) : Byte;
  129.  
  130. { Swap the lowest- and lowest-but-one-order bytes, mask out the
  131.   higher ones }
  132. function  Swap (x : LongestInt) : Word;
  133.  
  134. { Store the current directory name (on the given drive number if
  135.   drive <> 0) in s }
  136. procedure GetDir (Drive : Byte; var s : String);
  137.  
  138. { Dummy routine for compatibility. @@Use two overloaded versions
  139.   rather than varargs when possible. }
  140. procedure SetTextBuf (var f : Text; var Buf; ...);
  141.  
  142. { Mostly useless BP compatible variables }
  143. var
  144.   SelectorInc : Word = $1000;
  145.   Seg0040 : Word = $40;
  146.   SegA000 : Word = $a000;
  147.   SegB000 : Word = $b000;
  148.   SegB800 : Word = $b800;
  149.   Test8086 : Byte = 2;
  150.   Test8087 : Byte = 3; { floating-point arithmetic is emulated
  151.                          transparently by the OS if not present
  152.                          in hardware }
  153.   OvrCodeList : Word = 0;
  154.   OvrHeapSize : Word = 0;
  155.   OvrDebugPtr : Pointer = nil;
  156.   OvrHeapOrg : Word = 0;
  157.   OvrHeapPtr : Word = 0;
  158.   OvrHeapEnd : Word = 0;
  159.   OvrLoadList : Word = 0;
  160.   OvrDosHandle : Word = 0;
  161.   OvrEmsHandle : Word = $ffff;
  162.   HeapOrg : Pointer absolute HeapBegin;
  163.   HeapPtr : Pointer absolute HeapHigh;
  164.   HeapEnd : Pointer = Pointer (High (PtrCard));
  165.   FreeList : Pointer = nil;
  166.   FreeZero : Pointer = nil;
  167.   StackLimit : Word = 0;
  168.   HeapList : Word = 0;
  169.   HeapLimit : Word = 1024;
  170.   HeapBlock : Word = 8192;
  171.   HeapAllocFlags : Word = 2;
  172.   CmdShow : Integer = 0;
  173.   SaveInt00 : Pointer = nil;
  174.   SaveInt02 : Pointer = nil;
  175.   SaveInt0C : Pointer = nil;
  176.   SaveInt0D : Pointer = nil;
  177.   SaveInt1B : Pointer = nil;
  178.   SaveInt21 : Pointer = nil;
  179.   SaveInt23 : Pointer = nil;
  180.   SaveInt24 : Pointer = nil;
  181.   SaveInt34 : Pointer = nil;
  182.   SaveInt35 : Pointer = nil;
  183.   SaveInt36 : Pointer = nil;
  184.   SaveInt37 : Pointer = nil;
  185.   SaveInt38 : Pointer = nil;
  186.   SaveInt39 : Pointer = nil;
  187.   SaveInt3A : Pointer = nil;
  188.   SaveInt3B : Pointer = nil;
  189.   SaveInt3C : Pointer = nil;
  190.   SaveInt3D : Pointer = nil;
  191.   SaveInt3E : Pointer = nil;
  192.   SaveInt3F : Pointer = nil;
  193.   SaveInt75 : Pointer = nil;
  194.   RealModeRegs : array [0 .. 49] of Byte =
  195.     (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  196.      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  197.      0, 0, 0, 0, 0, 0, 0, 0);
  198.  
  199. { Mostly useless BP compatible pointer functions }
  200. function  Ofs (const X) : PtrWord;
  201. function  Seg (const X) : PtrWord;
  202. function  Ptr (Seg, Ofs : PtrWord) : Pointer;
  203. function  CSeg : PtrWord;
  204. function  DSeg : PtrWord;
  205. function  SSeg : PtrWord;
  206. function  SPtr : PtrWord;
  207.  
  208. {
  209.   Routines to handle BP's 6 byte `Real' type which is formatted like
  210.   this:
  211.  
  212.   47                                                   0
  213.   -|------- -------- -------- -------- --------|--------
  214.    |                                           |
  215.    +----------+                   +------------+
  216.   47 Sign Bit |  8..46 Mantissa   | 0..7 Biased Exponent
  217.  
  218.   This format does not support infinities, NaNs and denormalized
  219.   numbers. The first digit after the binary point is not stored and
  220.   assumed to be 1. (This is called the normalized representation of
  221.   a binary floating point number.)
  222.  
  223.   In GPC, this type is represented by the type `BPReal' which is
  224.   binary compatible to BP's type, and can therefore be used in
  225.   connection with binary files used by BP programs.
  226.  
  227.   The functions `RealToBPReal' and `BPRealToReal' convert between
  228.   this type and GPC's `Real' type. Apart from that, `BPReal' should
  229.   be treated as opaque.
  230.  
  231.   The variables `BPRealIgnoreOverflow' and `BPRealIgnoreUnderflow'
  232.   determine what to do in the case of overflows and underflows. The
  233.   default values are BP compatible.
  234. }
  235.  
  236. var
  237.   { Ignore overflows, and use the highest possible value instead. }
  238.   BPRealIgnoreOverflow  : Boolean = False;
  239.  
  240.   { Ignore underflows, and use 0 instead. This is BP's behaviour,
  241.     but has the disadvantage of diminishing computation precision. }
  242.   BPRealIgnoreUnderflow : Boolean = True;
  243.  
  244. type
  245.   BPReal = record
  246.     Format : array [1 .. 6] of Cardinal (8)
  247.   end;
  248.  
  249. function RealToBPReal (R : Real) : BPReal;
  250. function BPRealToReal (const BR : BPReal) : Real;
  251.  
  252. { Heap management stuff }
  253.  
  254. const
  255.   { Possible return values for HeapError }
  256.   HeapErrorRunError = 0;
  257.   HeapErrorNil      = 1;
  258.   HeapErrorRetry    = 2;
  259.  
  260. var
  261.   { If assigned to a function, it will be called when memory
  262.     allocations do not find enough free memory. Its return value
  263.     determines if a run time error should be raised (the default),
  264.     or nil should be returned, or the allocation should be retried
  265.     (causing the routine to be called again if the allocation still
  266.     doesn't succeed).
  267.  
  268.     Notes:
  269.  
  270.     - Returning nil can cause some routines of the RTS and units
  271.       (shipped with GPC or third-party) to crash when they don't
  272.       expect nil, so better don't use this mechanism, but rather
  273.       CGetMem where needed.
  274.  
  275.     - Letting the allocation be retried, of course, only makes sense
  276.       if the routine freed some memory before -- otherwise it will
  277.       cause an infinite loop! So, a meaningful HeapError routine
  278.       should dispose of some temporary objects, if available, and
  279.       return HeapErrorRetry, and return HeapErrorRunError when no
  280.       (more) of them are available.
  281.   }
  282.   HeapError : ^function (Size : Word) : Integer = nil;
  283.  
  284. { Just returns HeapErrorNil. When this function is assigned to
  285.   HeapError, GetMem and New will return a nil pointer instead of
  286.   causing a runtime error when the allocation fails. See the comment
  287.   for HeapError above. }
  288. function  HeapErrorNilReturn (Size : Word) : Integer;
  289.  
  290. { Return the total free memory/biggest free memory block. Except
  291.   under Win32 and DJGPP, these are expensive routines -- try to
  292.   avoid them. Under Win32, MaxAvail returns the same as MemAvail, so
  293.   don't rely on being able to allocate a block of memory as big as
  294.   MaxAvail indicates. Generally it's preferable to not use these
  295.   functions at all in order to do a safe allocation, but just try to
  296.   allocate the memory needed using CGetMem, and check for a nil
  297.   result. What makes these routines unrealiable is, e.g., that on
  298.   multi-tasking systems, another process may allocate memory after
  299.   you've called MemAvail/MaxAvail and before you get to do the next
  300.   allocation. Also, please note that some systems over-commit
  301.   virtual memory which may cause MemAvail to return a value larger
  302.   than the actual (physical plus swap) memory available. Therefore,
  303.   if you want to be "sure" (modulo the above restrictions) that the
  304.   memory is actually available, use MaxAvail. }
  305. function  MemAvail : Cardinal;
  306. function  MaxAvail : Cardinal;
  307.  
  308. implementation
  309.  
  310. function Lo (x : LongestInt) : Byte;
  311. begin
  312.   Lo := LongestCard (x) and $ff
  313. end;
  314.  
  315. function Hi (x : LongestInt) : Byte;
  316. begin
  317.   Hi := (LongestCard (x) div $100) and $ff
  318. end;
  319.  
  320. function Swap (x : LongestInt) : Word;
  321. begin
  322.   Swap := (LongestCard (x) and $ff) * $100 + (LongestCard (x) div $100) and $ff
  323. end;
  324.  
  325. procedure GetDir (Drive : Byte; var s : String);
  326. begin
  327.   if Drive = 0
  328.     then s := FExpand (DirSelf)
  329.     else s := FExpand (Succ ('a', Drive - 1) + ':')
  330. end;
  331.  
  332. procedure SetTextBuf (var f : Text; var Buf; ...);
  333. begin
  334. end;
  335.  
  336. function Ofs (const X) : PtrWord;
  337. begin
  338.   Ofs := PtrWord (@X)
  339. end;
  340.  
  341. function Seg (const X) : PtrWord;
  342. begin
  343.   Seg := 0
  344. end;
  345.  
  346. function Ptr (Seg, Ofs : PtrWord) : Pointer;
  347. begin
  348.   Ptr := Pointer ($10 * Seg + Ofs)
  349. end;
  350.  
  351. type
  352.   PointerType = ^Integer; { any typed pointer will do }
  353.  
  354. function CSeg : PtrWord;
  355. begin
  356.   CSeg := Seg (PointerType (ReturnAddress (0))^)
  357. end;
  358.  
  359. function DSeg : PtrWord;
  360. begin
  361.   DSeg := Seg (ExitProc) { any global variable will do }
  362. end;
  363.  
  364. function SSeg : PtrWord;
  365. begin
  366.   SSeg := Seg (PointerType (FrameAddress (0))^)
  367. end;
  368.  
  369. function SPtr : PtrWord;
  370. begin
  371.   SPtr := Ofs (PointerType (FrameAddress (0))^)
  372. end;
  373.  
  374. function RealToBPReal (R : Real) = BR : BPReal;
  375. var
  376.   Mantissa : Extended;
  377.   Exponent, Sign, X : OrigInt;
  378. begin
  379.   for X := 1 to 6 do BR.Format [X] := 0;
  380.   if IsNotANumber (R) then
  381.     RuntimeError (870) { BP compatible 6 byte `Real' type does not support NaNs }
  382.   else if IsInfinity (R) then
  383.     RuntimeError (871) { BP compatible 6 byte `Real' type does not support infinity }
  384.   else
  385.     begin
  386.       SplitReal (R, Exponent, Mantissa);
  387.       Inc (Exponent, $80);
  388.       Sign := 0;
  389.       if Mantissa < 0 then
  390.         begin
  391.           Mantissa := - Mantissa;
  392.           Sign := 1
  393.         end;
  394.       if Exponent < 0 then { number cannot be stored in BPReal due to an underflow }
  395.         if BPRealIgnoreUnderflow then
  396.           { Set BR to zero -- BR is pre-initialized with 0 already }
  397.         else
  398.           RuntimeError (872) { underflow while converting to BP compatible 6 byte `Real' type }
  399.       else if Exponent > 255 then
  400.         if BPRealIgnoreOverflow then
  401.           begin
  402.             { Set BR to highest number representable in this format }
  403.             for X := 1 to 6 do BR.Format [X] := $ff;
  404.             and (BR.Format [6], not ((not Sign) shl 7)) { Set sign }
  405.           end
  406.         else
  407.           RuntimeError (873) { overflow while converting to BP compatible 6 byte `Real' type }
  408.       else
  409.         begin
  410.           { Convert a non-infinite number }
  411.           BR.Format [1] := Exponent;
  412.           Mantissa := Mantissa * 2;
  413.           if Mantissa < 1 then { if R is normalized, first bit is set }
  414.             if BPRealIgnoreUnderflow then
  415.               { Set BR to zero -- BR is pre-initialized with 0 already }
  416.             else
  417.               RuntimeError (874) { cannot convert denormalized number to BP compatible 6 byte `Real' type }
  418.           else
  419.             begin
  420.               { Leave out the first bit }
  421.               Mantissa := Mantissa - 1;
  422.               for X := 1 to 39 do
  423.                 begin
  424.                   Mantissa := Mantissa * 2;
  425.                   if Mantissa >= 1 then
  426.                     begin
  427.                       or (BR.Format [6 - X div 8], 1 shl (7 - X mod 8));
  428.                       Mantissa := Mantissa - 1
  429.                     end
  430.                 end;
  431.               { Set sign }
  432.               and (BR.Format [6], not (1 shl 7));
  433.               or (BR.Format [6], Sign shl 7)
  434.             end
  435.         end
  436.     end
  437. end;
  438.  
  439. function BPRealToReal (const BR : BPReal) = RealValue : Real;
  440. var
  441.   X : Cardinal;
  442.   Mantissa, e : Real;
  443. begin
  444.   Mantissa := 0.5;
  445.   e := 0.25;
  446.   { Leave out the first bit }
  447.   for X := 1 to 39 do
  448.     begin
  449.       Mantissa := Mantissa +
  450.         ((BR.Format [6 - X div 8] and (1 shl (7 - X mod 8))) shr (7 - X mod 8)) * e;
  451.       e := e / 2
  452.     end;
  453.   RealValue := Mantissa * Exp (Ln (2) * (BR.Format [1] - 128));
  454.   if BR.Format [6] and 128 <> 0 then
  455.     RealValue := - RealValue
  456. end;
  457.  
  458. { Heap management stuff }
  459.  
  460. var
  461.   OldGetMem    : GetMemType;
  462.   OldFreeMem   : FreeMemType;
  463.   MaxAvailSave : Pointer = nil;
  464.   MaxAvailSize : SizeType = 0;
  465.  
  466. function BPGetMem (Size : SizeType) = p : Pointer;
  467. var Status : Integer;
  468. begin
  469.   if (MaxAvailSave <> nil) and (Size <= MaxAvailSize) then
  470.     begin
  471.       if Size = MaxAvailSize
  472.         then p := MaxAvailSave
  473.         else p := CReAllocMem (MaxAvailSave, Size);
  474.       MaxAvailSave := nil;
  475.       MaxAvailSize := 0;
  476.       if p <> nil then Exit
  477.     end;
  478.   if HeapError = nil then
  479.     p := OldGetMem^ (Size)
  480.   else
  481.     begin
  482.       repeat
  483.         p := CGetMem (Size);
  484.         if p <> nil then Exit;
  485.         Status := HeapError^ (Size)
  486.       until Status <> HeapErrorRetry;
  487.       if Status = HeapErrorNil then p := UndocumentedReturnNil
  488.     end
  489. end;
  490.  
  491. procedure BPFreeMem (aPointer : Pointer);
  492. begin
  493.   if MaxAvailSave <> nil then
  494.     begin
  495.       CFreeMem (MaxAvailSave);
  496.       MaxAvailSave := nil;
  497.       MaxAvailSize := 0
  498.     end;
  499.   OldFreeMem^ (aPointer)
  500. end;
  501.  
  502. function HeapErrorNilReturn (Size : Word) : Integer;
  503. var Dummy : Word;
  504. begin
  505.   Dummy := Size;
  506.   HeapErrorNilReturn := HeapErrorNil
  507. end;
  508.  
  509. {$ifdef __DJGPP__}
  510.  
  511. type
  512.   DPMIFreeInfo = record
  513.     largest_available_free_block_in_bytes,
  514.     maximum_unlocked_page_allocation_in_pages,
  515.     maximum_locked_page_allocation_in_pages,
  516.     linear_address_space_size_in_pages,
  517.     total_number_of_unlocked_pages,
  518.     total_number_of_free_pages,
  519.     total_number_of_physical_pages,
  520.     free_linear_address_space_in_pages,
  521.     size_of_paging_file_partition_in_pages : Cardinal;
  522.     reserved : array [0..2] of Cardinal
  523.   end;
  524.  
  525. function DPMIGetFreeMemInfo (var Info : DPMIFreeInfo) : OrigInt;
  526.   asmname '__dpmi_get_free_memory_information';
  527.  
  528. function DPMIGetPageSize (var Size : Cardinal) : OrigInt;
  529.   asmname '__dpmi_get_page_size';
  530.  
  531. function MemAvail : Cardinal;
  532. var
  533.   D : DPMIFreeInfo;
  534.   W : Cardinal;
  535.   Dummy : OrigInt;
  536. begin
  537.   Dummy := DPMIGetFreeMemInfo (D);
  538.   Dummy := DPMIGetPageSize (W);
  539.   MemAvail := (D.total_number_of_unlocked_pages * W)
  540. end;
  541.  
  542. function MaxAvail : Cardinal;
  543. var
  544.   D : DPMIFreeInfo;
  545.   W : Cardinal;
  546.   Dummy : OrigInt;
  547. begin
  548.   Dummy := DPMIGetFreeMemInfo (D);
  549.   Dummy := DPMIGetPageSize (W);
  550.   MaxAvail := (D.total_number_of_free_pages * W)
  551. end;
  552.  
  553. {$elif defined (_WIN32)}
  554.  
  555. type
  556.   TMemoryStatus = record
  557.     dwLength,
  558.     dwMemoryLoad,
  559.     dwTotalPhys,
  560.     dwAvailPhys,
  561.     dwTotalPageFile,
  562.     dwAvailPageFile,
  563.     dwTotalVirtual,
  564.     dwAvailVirtual : OrigInt
  565.   end;
  566.  
  567. procedure GlobalMemoryStatus (var Buffer : TMemoryStatus);
  568.   asmname 'GlobalMemoryStatus'; attribute (stdcall);
  569.  
  570. function MemAvail : Cardinal;
  571. var T : TMemoryStatus;
  572. begin
  573.   T.dwLength := SizeOf (TMemoryStatus);
  574.   GlobalMemoryStatus (T);
  575.   MemAvail := Min (T.dwAvailPhys + T.dwAvailPageFile, T.dwAvailVirtual)
  576. end;
  577.  
  578. function MaxAvail : Cardinal;
  579. begin
  580.   MaxAvail := MemAvail
  581. end;
  582.  
  583. {$else}
  584.  
  585. const
  586.   { Parameters for MemAvail and MaxAvail }
  587.   StartSize     = $100000; { 1MB }
  588.   MinSize       = $10;
  589.   PrecisionBits = 5;
  590.  
  591. function FindLargestMemBlock (var p : Pointer) : SizeType;
  592. var
  593.   Size, Step : SizeType;
  594.   Bits : OrigInt;
  595. begin
  596.   Size := StartSize;
  597.   p := CGetMem (Size);
  598.   while p <> nil do
  599.     begin
  600.       Size := 2 * Size;
  601.       CFreeMem (p);
  602.       p := CGetMem (Size)
  603.     end;
  604.   repeat
  605.     Size := Size div 2;
  606.     p := CGetMem (Size)
  607.   until (p <> nil) or (Size <= MinSize);
  608.   Bits := PrecisionBits;
  609.   Step := Size;
  610.   while (Bits > 0) and (Size >= 2 * MinSize) and (p <> nil) do
  611.     begin
  612.       Dec (Bits);
  613.       CFreeMem (p);
  614.       Inc (Size, Step);
  615.       Step := Step div 2;
  616.       repeat
  617.         Dec (Size, Step);
  618.         p := CGetMem (Size)
  619.       until (p <> nil) or (Size <= MinSize)
  620.     end;
  621.   if p = nil then
  622.     Size := 0
  623.   else if Size = 0 then
  624.     p := nil;
  625.   FindLargestMemBlock := Size
  626. end;
  627.  
  628. function MaxAvail : Cardinal;
  629. begin
  630.   if MaxAvailSave <> nil then CFreeMem (MaxAvailSave);
  631.   MaxAvailSize := FindLargestMemBlock (MaxAvailSave);
  632.   MaxAvail := MaxAvailSize
  633. end;
  634.  
  635. function MemAvail : Cardinal;
  636. type
  637.   PMemList = ^TMemList;
  638.   TMemList = record
  639.     Next : PMemList
  640.   end;
  641. var
  642.   TotalSize, NewSize : SizeType;
  643.   MemList, p : PMemList;
  644.   LargeEnough : Boolean;
  645. begin
  646.   TotalSize := MaxAvail;
  647.   MemList := nil;
  648.   repeat
  649.     NewSize := FindLargestMemBlock (p);
  650.     Inc (TotalSize, NewSize);
  651.     LargeEnough := (NewSize >= SizeOf (p^)) and (NewSize >= TotalSize shr PrecisionBits);
  652.     if LargeEnough then
  653.       begin
  654.         p^.Next := MemList;
  655.         MemList := p
  656.       end
  657.   until not LargeEnough;
  658.   if p <> nil then CFreeMem (p);
  659.   while MemList <> nil do
  660.     begin
  661.       p := MemList;
  662.       MemList := MemList^.Next;
  663.       CFreeMem (p)
  664.     end;
  665.   MemAvail := TotalSize
  666. end;
  667. {$endif}
  668.  
  669. {$ifdef __BP_RANDOM__}
  670. { BP compatible random number generator }
  671. procedure NextRand;
  672. begin
  673.   (*@@$localR-*) RandSeed := $8088405 * RandSeed + 1 (*@@$endlocal*)
  674. end;
  675.  
  676. function BP_RandInt (Range : LongestCard) : LongestCard;
  677. type Card64 = Cardinal (64);
  678. begin
  679.   NextRand;
  680.   BP_RandInt := (Card64 (RandSeed) * (Range mod $10000)) div $100000000
  681. end;
  682.  
  683. function BP_RandReal : LongestReal;
  684. begin
  685.   NextRand;
  686.   BP_RandReal := RandSeed /$10000/$10000(*@@(fjf481.pas)/ $100000000*) + 0.5
  687. end;
  688.  
  689. procedure BP_SeedRandom (Seed : RandomSeedType);
  690. begin
  691.   RandSeed := Seed
  692. end;
  693.  
  694. procedure BP_Randomize;
  695. var Time : TimeStamp;
  696. begin
  697.   GetTimeStamp (Time);
  698.   with Time do BP_SeedRandom (((Second * $100 + (MicroSecond div 10000)) * $100 + Hour) * $100 + Minute)
  699. end;
  700. {$endif}
  701.  
  702. to begin do
  703.   begin
  704.     OldGetMem     := GetMemPtr;
  705.     OldFreeMem    := FreeMemPtr;
  706.     GetMemPtr     := @BPGetMem;
  707.     FreeMemPtr    := @BPFreeMem;
  708.     {$ifdef __BP_RANDOM__}
  709.     RandomizePtr  := @BP_Randomize;
  710.     SeedRandomPtr := @BP_SeedRandom;
  711.     RandRealPtr   := @BP_RandReal;
  712.     RandIntPtr    := @BP_RandInt;
  713.     {$endif}
  714.     var CmdLineStr : static TString;
  715.     var i : OrigInt;
  716.     CmdLineStr := ParamStr (1);
  717.     for i := 2 to ParamCount do CmdLineStr := CmdLineStr + ' ' + ParamStr (i);
  718.     CmdLine := CmdLineStr
  719.   end;
  720.  
  721. to end do
  722.   while ExitProc <> nil do
  723.     begin
  724.       var Tmp : ^procedure;
  725.       Tmp := ExitProc;
  726.       ExitProc := nil;
  727.       Tmp^
  728.     end;
  729. end.
  730.